/*
 *  Copyright 2011 yura.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package org.opu.vcforms.transform_t2d.util.smart_xml;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author yura
 */
public class TextMarkupUtil {
    public static final String DEFAULT_NAME = "DEFAULT";
    /** {@code #<content name>}{; */
    public static final Pattern CONTENT_START = Pattern.compile("\\#[^\\;]+\\{\\;");
    /** #}{@code <content name>}; */
    public static final Pattern CONTENT_END = Pattern.compile("\\#\\}[^\\;]+\\;");
    /** {@code $<variable name>; } */
    public static final Pattern VARIABLE = Pattern.compile("\\$[^\\;]+\\;");

    /**
     * Divide string on to list of lexem
     * @param text dividing string
     * @return list of lexem
     */
    public static List<Lexem> split(String text){
        // 1 - content start
        Matcher contentStart = CONTENT_START.matcher(text);
        List<Lexem> list = split0(contentStart, text, LexemType.CONTENT_START);

        // 2 - content end
        list = split1(list, CONTENT_END, LexemType.CONTENT_END);

        // 3 - var
        list = split1(list, VARIABLE, LexemType.VARIABLE);

        // 4 - replace null type to text
        for (Lexem lexem : list) {
            if (lexem.type == null){
                lexem.type = LexemType.TEXT;
            }
        }

        // 5 - for all not text type left only it names
        for (Lexem lexem : list) {
            if (lexem.type != LexemType.TEXT && lexem.text.length() < 2){
                lexem.text = DEFAULT_NAME;
            } else {
                if (lexem.type == LexemType.CONTENT_START){
                    lexem.text = lexem.text.substring(1, lexem.text.length() -2);
                } else if (lexem.type == LexemType.CONTENT_END){
                    lexem.text = lexem.text.substring(2, lexem.text.length() -1);
                } else if (lexem.type == LexemType.VARIABLE){
                    lexem.text = lexem.text.substring(1, lexem.text.length() -1);
                }
            }
        }

        // 6 - remove all empty text
        for (Iterator<Lexem> it = list.iterator(); it.hasNext();) {
            Lexem lexem = it.next();
            if((lexem.type == LexemType.TEXT)
                    && (lexem.text == null || lexem.text.isEmpty())){
                it.remove();
            }
        }

        return list;
    }

    private static List<Lexem> split1(List<Lexem> list, Pattern patern, LexemType type){
        List<Lexem> list1 = new ArrayList<Lexem>();
        for (Lexem lexem : list) {
            if (lexem.type == null){
                Matcher contentEnd = patern.matcher(lexem.text);
                list1.addAll(split0(contentEnd, lexem.text, type));
            } else {
                list1.add(lexem);
            }
        }
        return list1;
    }
    
    private static List<Lexem> split0(Matcher contentStart, String text, LexemType type) {
        List<Lexem> list = new ArrayList<Lexem>();
        int start = 0;
        int end = 0;
        while (contentStart.find()) {
            int last = end;
            start = contentStart.start();
            end = contentStart.end();
            list.add(new Lexem(text.substring(last, start), null));
            list.add(new Lexem(text.substring(start, end), type));
        }
        if (end < text.length()) {
            list.add(new Lexem(text.substring(end), null));
        }
        return list;
    }

    public static enum LexemType{
        CONTENT_START, CONTENT_END, VARIABLE, TEXT
    }

    public static class Lexem implements Serializable{
        private String text;
        private LexemType type;

        public Lexem(String text, LexemType type) {
            this.text = text;
            this.type = type;
        }

        public String getText() {
            return text;
        }

        public LexemType getType() {
            return type;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }

            if (getClass() != obj.getClass()) {
                return false;
            }

            final Lexem other = (Lexem) obj;
            if ((this.text == null) ? (other.text != null) : !this.text.equals(other.text)) {
                return false;
            }

            if (this.type != other.type) {
                return false;
            }

            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 11 * hash + (this.text != null ? this.text.hashCode() : 0);
            hash = 11 * hash + (this.type != null ? this.type.hashCode() : 0);
            return hash;
        }

        @Override
        public String toString() {
            return "Lexem{" + "text='" + text + "' type=" + type + '}';
        }
    }
}
